package com.stylefeng.guns.modular.pay.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.xml.bind.JAXBException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baidu.unbiz.fluentvalidator.FluentValidator;
import com.baidu.unbiz.fluentvalidator.Result;
import com.baidu.unbiz.fluentvalidator.ResultCollectors;
import com.baidu.unbiz.fluentvalidator.jsr303.HibernateSupportedValidator;
import com.stylefeng.guns.modular.pay.dao.WithdrawOrderMapper;
import com.stylefeng.guns.modular.pay.model.AllinMch;
import com.stylefeng.guns.modular.pay.model.WithdrawOrder;
import com.stylefeng.guns.modular.pay.payment.allin.common.api.ApiRsp;
import com.stylefeng.guns.modular.pay.payment.allin.common.api.RpcSingleTranxReq;
import com.stylefeng.guns.modular.pay.payment.allin.common.api.RpcTransQueryReq;
import com.stylefeng.guns.modular.pay.payment.allin.common.core.XmlTools;
import com.stylefeng.guns.modular.pay.payment.allin.common.entity.common.AipgReq;
import com.stylefeng.guns.modular.pay.payment.allin.common.entity.common.AipgRsp;
import com.stylefeng.guns.modular.pay.payment.allin.common.entity.common.InfoReq;
import com.stylefeng.guns.modular.pay.payment.allin.common.entity.common.XSUtil;
import com.stylefeng.guns.modular.pay.payment.allin.common.entity.rtreq.Trans;
import com.stylefeng.guns.modular.pay.payment.allin.common.entity.transquery.TransQueryReq;
import com.stylefeng.guns.modular.pay.payment.allin.common.exception.AllInPayBizException;
import com.stylefeng.guns.modular.pay.payment.allin.common.utils.AllinPayUtils;
import com.stylefeng.guns.modular.pay.service.AllInPayService;
import com.stylefeng.guns.modular.pay.util.JaXmlBeanUtil;

@Service
public class AllInPayServiceImpl implements AllInPayService {
	private static final Logger LOGGER = LoggerFactory.getLogger(AllInPayServiceImpl.class);
	@Autowired
	private WithdrawOrderMapper withdrawOrderMapper;
	
	@Autowired
	private static Validator validator;

	static {
		Locale.setDefault(Locale.ENGLISH);
		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
		validator = factory.getValidator();
	}

	@Override
	public Object batchTranx() throws AllInPayBizException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object refundTranx() throws AllInPayBizException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ApiRsp singleTranx(RpcSingleTranxReq req, AllinMch config) throws AllInPayBizException {
		Result validatorResult = FluentValidator.checkAll()
				.on(req, new HibernateSupportedValidator<RpcSingleTranxReq>().setHiberanteValidator(validator))
				.doValidate().result(ResultCollectors.toSimple());
		if (!validatorResult.isSuccess()) {
			String error = validatorResult.getErrors().get(0);
			LOGGER.info("业务校验错误:"+error);
			throw new AllInPayBizException(AllInPayBizException.Code.BUS_VALIDATE_ERROR,validatorResult.getErrors().get(0));
		}
		if(!new File(config.getCerPath()).exists()){
			LOGGER.info("配置文件不存在");
			throw new AllInPayBizException(AllInPayBizException.Code.CONFIG_FILE_UNEXIST);
		}
		AipgReq aipg = new AipgReq();
		InfoReq info = AllinPayUtils.makeReq("100014", config,req.getReq_sn());
		aipg.setINFO(info);
		Trans trans = new Trans();
		// 必填参数
		trans.setBUSINESS_CODE("09900");
		trans.setMERCHANT_ID(config.getMerchantId());
		trans.setSUBMIT_TIME(req.getSubmitTime());
		trans.setACCOUNT_NAME(req.getAccountName());
		trans.setACCOUNT_NO(req.getAccountNo());
		trans.setAMOUNT(req.getAmount());
		// 选填
		trans.setACCOUNT_PROP(req.getAccountProp());
		trans.setACCOUNT_TYPE(req.getAccountType());
		trans.setBANK_CODE(req.getBankCode());
		trans.setCURRENCY(req.getCurrency());
		trans.setCUST_USERID(req.getCustUserid());
		trans.setTEL(req.getTel());
		trans.setVALIDATE(req.getValidate());
		trans.setCVV2(req.getCvv2());
		trans.setSUMMARY(req.getSummary());
		trans.setREMARK(req.getRemark());

		aipg.addTrx(trans);
		String xml = XmlTools.buildXml(aipg, true);
		LOGGER.info("请求xml="+xml);
		String retXml = "";
		try {
			retXml = AllinPayUtils.sendToTlt(xml, false,config,"https://tlt.allinpay.com/aipg/ProcessServlet");
		} catch (Exception e) {
			throw new AllInPayBizException(AllInPayBizException.Code.CHANNEL_REQ_ERROR);
		}
		LOGGER.info("返回xml="+retXml);
		ApiRsp aipgrsp = null;
		try {
			aipgrsp = JaXmlBeanUtil.xmlToBean(retXml, ApiRsp.class);
		} catch (JAXBException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return aipgrsp;
	}

	@Override
	public Object downBills() throws AllInPayBizException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object signNotice() throws AllInPayBizException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object singleAcctVerify() throws AllInPayBizException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object acctBalance() throws AllInPayBizException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ApiRsp queryTranx(RpcTransQueryReq req, AllinMch config) throws AllInPayBizException {
		Result validatorResult = FluentValidator.checkAll()
				.on(req, new HibernateSupportedValidator<RpcTransQueryReq>().setHiberanteValidator(validator))
				.doValidate().result(ResultCollectors.toSimple());
		if (!validatorResult.isSuccess()) {
			throw new AllInPayBizException(AllInPayBizException.Code.BUS_VALIDATE_ERROR,validatorResult.getErrors().get(0));
		}
		if(!new File(config.getCerPath()).exists()){
			throw new AllInPayBizException(AllInPayBizException.Code.CONFIG_FILE_UNEXIST);
		}

		AipgReq aipgReq = new AipgReq();
		InfoReq info = AllinPayUtils.makeReq("200004", config,"");
		aipgReq.setINFO(info);
		TransQueryReq dr = new TransQueryReq();
		dr.setMERCHANT_ID(config.getMerchantId());
		dr.setQUERY_SN(req.getQuerySn());
		dr.setSTATUS(Integer.valueOf(req.getStatus()));
		dr.setTYPE(Integer.valueOf(req.getType()));
		if (req.getQuerySn() == null || "".equals(req.getQuerySn())) {
			dr.setSTART_DAY(req.getStartDay());
			dr.setEND_DAY(req.getEndDay());
		}
		aipgReq.addTrx(dr);
		String xml = XmlTools.buildXml(aipgReq, true);
		LOGGER.info("请求xml="+xml);
		String retXml = "";
		try {
			retXml = AllinPayUtils.sendToTlt(xml, false,config, "https://tlt.allinpay.com/aipg/ProcessServlet");
		} catch (Exception e) {
			e.printStackTrace();
		}
		LOGGER.info("返回xml="+retXml);
		ApiRsp aipgrsp = null;
		try {
			aipgrsp = JaXmlBeanUtil.xmlToBean(retXml, ApiRsp.class);
		} catch (JAXBException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return aipgrsp;
	}
	

	@Override
	public void notify(Map<String, String> params, WithdrawOrder order) {
		String retCode = params.get("RETCODE");
		if("0000".equals(retCode) && order.getStatus()!=3){
			order.setStatus(3);
			order.setRetCode(retCode);
			order.setErrMsg(params.get("RETMSG"));
			order.setFinTime(params.get("FINTIME"));
			order.setSettleDay(params.get("SETTDAY"));
			withdrawOrderMapper.updateById(order);
			LOGGER.info("订单处理成功!!："+order.getPlatTradeNo());
		
		}else if(("2000".equals(retCode)||"2001".equals(retCode)||"2003".equals(retCode)
				||"2005".equals(retCode)||"2007".equals(retCode)||"2008".equals(retCode)) && order.getStatus()!=2){
			order.setStatus(2);
			order.setRetCode(retCode);
			order.setErrMsg(params.get("RETMSG"));
			withdrawOrderMapper.updateById(order);
			LOGGER.info("订单处理中!!："+order.getPlatTradeNo());
		}else{
			order.setStatus(4);
			order.setRetCode(retCode);
			order.setErrMsg(params.get("RETMSG"));
			LOGGER.info("订单处理失败!!："+order.getPlatTradeNo());
			withdrawOrderMapper.updateById(order);
		}
	}

}
